using System;
using System.Collections.Generic;
using System.Text;

namespace SIM_TPN_1a
{   

    public class Generador
    {
        //Atributos generales
        private int seed = 0;
        private int seedAnt = 0;
        private int metodo = 0;

        //Constantes del metodo Congruencial
        int c = 443; //cualquier entero impar no divisible ni por 3 ni por 5. Ej: 7

        public int C
        {
            get { return c; }
            set { c = value; }
        }
        int a = 13; //a mod 8 = 5

        public int A
        {
            get { return a; }
            set { a = value; }
        }
        int m = 767; //el entero mas grande que acepte la computadora 

        public int M
        {
            get { return m; }
            set { m = value; }
        }
                    // en este caso un int (2147483647)
                    // en el libro 767
           
        public static int  METODO_MEDIOS_CUADRADOS = 1;
        public static int  METODO_CONGRUENCIAL_MIXTO = 2;
        public static int  METODO_CONGRUENCIAL_ADITIVO = 3;

        public double generar(int metodo, int seed) {
            if (seed != 0) {
                this.seed = seed;
            } else {
                return -1; //error -1: seed no especificado
            }
            this.metodo = metodo;
            switch (metodo) {
                case 1:
                    this.seed = this.mediosCuadrados(seed);
                    return (double)Math.Round((double)(this.seed * 0.0001), 4);
                case 2:
                    this.seed = this.congruencialMixto(seed);
                    return (double)((double)this.seed / (double)(this.m - 1));
                default:
                    return -2;//error -2: metodo incorrecto
            }
            //return (double) this.seed * 0.0001;
        }

        public double generar(int metodo, int seed1, int seed2)
        {
            if (seed1 != 0 || seed2 != 0)
            {
                this.seed = seed1;
                this.seedAnt = seed2;
            }
            else
            {
                return -1; //error -1: seed no especificado
            }
            this.metodo = metodo;
            switch (metodo)
            {
                case 3:
                    int tmpSeed = this.congruencialAditivo(seed1, seed2);
                    this.seedAnt = this.seed;
                    this.seed = tmpSeed;
                    return (double)((double)this.seed / (double)(this.m - 1));
                default:
                    return -2;//error -2: metodo incorrecto
            }
            //return (double) this.seed * 0.0001;
        }

        public double generar() {
            if (this.metodo == Generador.METODO_CONGRUENCIAL_ADITIVO)
                return generar(this.metodo, this.seed, this.seedAnt);
            else
                return generar(this.metodo, this.seed);
        }
         
        private int mediosCuadrados(int seed) {
            long resultado = seed;
            String sResult = "";
            resultado = resultado * resultado;
            sResult = "00000000" + resultado.ToString();
            sResult = sResult.Substring(sResult.Length - 6, 4);
            resultado = Convert.ToInt64(sResult);
            return (int) resultado;
        }

        private int congruencialMixto(int seed)
        {
            long resultado = (this.c + this.a * seed) % this.m;
            
            return (int) resultado;
        }

        private int congruencialAditivo(int seed1, int seed2)
        {
            long resultado = (seed1 + seed2) % this.m;
            return (int)resultado;
        }
    }
}

    

    

